import sys
import os
import time
import threading

from PyQt5.QtCore import QObject, pyqtSlot
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import *


from construct import Struct, Bytes, Int8ub, Int16ub, Checksum

from drivers.driver_serial import scan_serial_ports, SerialDevice

from common.qt_worker import Worker
from common.qt_task import TaskWorker






# from ui.Ui_serial_widget import Ui_SerialWidget
# from common.qt_worker import Worker
# from common.utils import *
# from drivers.driver_serial import scan_serial_ports, SerialDevice
# from ui.Ui_main_window import Ui_MainWindow
from ui.Ui_mbus_com import Ui_mbus_com
from ui.Ui_serial_widget import Ui_SerialWidget

from views.serial_widget import *

sys.path.append("../ui")


# 获取地址1 数据格式
mbus_get_addr_format = Struct(
    "header" / Bytes(2),  # 头部 3 字节
    "addr" / Bytes(7),  # 地址
    "cmd" / Bytes(1),  # 命令字段
    "length" / Bytes(1),  # 长度字段
    "data_cmd" / Bytes(2),  # 控制域
    "ser" / Bytes(1),  # SER计数
    "data" / Bytes(1),  # 数据
    "sum_cs" / Bytes(1),  # 累加和校验
    "end" / Bytes(1),  # 尾部标记
)


class My_mbus_com_Widget(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        
        # 在程序初始化时注册类型
        #qRegisterMetaType('QTextBlock')

        self.serial_widget: SerialWidget = None  # 类型声明

        self.main_window: QMainWindow = parent

        self.ui = Ui_mbus_com()
        self.ui.setupUi(self)

        # 获取 serial_widget 的引用
        self.serial_widget = self.window().findChild(
            QWidget, "serial_widget"
        )  # 对象名需在初始化时设置

        self.init_ui()

    def do_task(self, cmd_str):

        send_count = 3  # 单位 次
        send_delay = 5  # 单位 秒

        print("发送命令了")

        print(cmd_str)

        #self.ui.edit_addr_get.clear()  # 清空框

        # original_timeout = self.serial_widget.cur_serial_device.timeout
        # print("串口超时：", original_timeout)
        # self.serial_widget.cur_serial_device.timeout = 0.2
        
        
        # original_timeout = self.serial_widget.cur_serial_device.timeout
        # print("串口超时：", original_timeout)

        while send_count > 0:
            send_count -= 1

            try:
                self.serial_widget.cur_serial_device.write(cmd_str)  # 发送数据
            except Exception as e:
                print("发送数据异常：", e)

            # if self.cur_serial_device is None:
            #     break

            # if not self.cur_serial_device.is_open():
            #     break
            while send_delay > 0:
                data = (
                    # self.serial_widget.cur_serial_device.readline() #这个读取一行数据，超时时间无作用，不知道为啥
                    self.serial_widget.cur_serial_device.read(1000)
                )  # 此处利用串口超时进行延时

                #print("串口超时或接收完毕数据！！")

                if data:
                    print("串口收到回复内容")
                    #print(data)
                    try: 
                        data_hex = decode_to_hex_str(data)  # 转为16进制字符串
                    except Exception as e:
                        print("数据解析异常：", e)
                        
                    #print(f"{data_hex}")
                    self.ui.edit_addr_get.clear()  # 清空框
                    self.ui.edit_addr_get.appendPlainText(f"{data_hex}")

                    # self.ui.edit_addr_get.appendPlainText(f"{data}")
                    return True
                else:
                    send_delay -= 1
                    print("读取等待剩余秒数：{send_delay}", send_delay)
            print("剩余次数：{send_count}", send_count)
            print("读取等待超时")
            return False
        print("直接退出")

    @pyqtSlot(object)
    def on_result(result):
        # print(threading.currentThread())
        print("执行结果 result: ", result)

    @pyqtSlot(Exception)
    def on_error(e):
        # print(threading.currentThread())
        print("on error: ", e)

    def f_uart_send_thread(self, hex_str: str):
        """
        单线程循环接收消息
        :return:
        """
        self.task_worker = TaskWorker(self.do_task)

        self.task_worker.signal_connect(
            result_handler=self.on_result,
            finished_handler=lambda: print("处理完成"),
            error_handler=self.on_error,
        )
        self.task_worker.start()

        self.task_worker.join_queue(hex_str)

    def f_mbus_get_addr(self):

        # if self.ui.cur_serial_device is None or not self.cur_serial_device.is_open():
        #     print("请先打开串口")
        #     return

        if not self.serial_widget.check_serial_status():
            print("请先打开串口")
            return  # 串口未打开

        print("mbus get addr button clicked")

        text = self.ui.edit_addr_get.toPlainText()  # 获取输入框内容

        # 向串口发送数据 字符串发送
        # self.serial_widget.cur_serial_device.write(f"{text}".encode("utf-8"))

        try:
            # 将输入的文本转换为十六进制数据
            # 移除可能存在的空格
            text = text.replace(" ", "")
            # 将十六进制字符串转换为字节数据
            data = bytes.fromhex(text)
            # 向串口发送数据
            # self.serial_widget.cur_serial_device.write(data)
        except ValueError:
            print("输入的数据不是有效的十六进制格式")

            # 创建一个字典，包含每个字段的具体值
        command_packet = dict(
            header=b"\x68\x55",  # 固定头
            addr=b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa",  # 地址
            cmd=b"\x23",  # 命令
            length=b"\04",  # 长度，例如 0x2097 (在 Python 中表示为整数)
            data_cmd=b"\x81\x0a",  # 数据段
            ser=b"\x01",  # 标志位
            data=b"\x00",
            sum_cs=b"\x16",  # 标志位
            end=b"\x16",  # CRC 校验
        )

        # 使用 protocol_format.build() 方法构建二进制数据
        output_data = mbus_get_addr_format.build(command_packet)

        # 打印输出，通常你会将 output_data 发送到串口或其他通信接口
        print(output_data.hex().upper())  # 转换为大写的十六进制字符串进行显示
        # self.serial_widget.cur_serial_device.write(output_data)

        self.f_uart_send_thread(output_data)

    def f_mbus_set_addr(self):
        print("mbus set addr button clicked")
        pass

    def init_ui(self):
        self.ui.btn_mbus_get_addr.clicked.connect(self.f_mbus_get_addr)
        self.ui.btn_mbus_set_addr.clicked.connect(self.f_mbus_set_addr)
        pass


if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = My_mbus_com_Widget()
    window.show()

    sys.exit(app.exec_())
